package com.itheima.health.controller;

import com.itheima.health.common.MessageConst;
import com.itheima.health.entity.Result;

import com.itheima.health.pojo.OperationDataStatistics;

import com.itheima.health.service.MemberService;
import com.itheima.health.service.OrderService;
import com.itheima.health.service.ReportService;
import com.itheima.health.service.SetMealService;


import lombok.extern.slf4j.Slf4j;

import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;

import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.web.bind.annotation.GetMapping;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletResponse;

import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;


import java.io.OutputStream;

import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 数据报告控制器
 */
@RestController
@RequestMapping("/report")
@Slf4j
public class ReportController {
    @Autowired
    private SetMealService setMealService;
    @Autowired
    private OrderService orderService;


    @Autowired
    private MemberService memberService;

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 获取套餐预约占比的统计数据(套餐名 套餐对应的订单人数 算占比)
     *
     * @return
     */
    @GetMapping("/getSetmealReport")
    public Result getSetmealReport() {
        log.info("[查询各个预约套餐占比]");
        List<Map<String, Object>> list = setMealService.getSetmealCount();



        //1:获取所有套餐 放到List里 map里是单个套餐的套餐数量和所有套餐
        //调用业务层获取所有套餐放到List里
        Map<String, Object> map = new HashMap<>();

        //2:把套餐存到map里  以键值对的形式  键是套餐名字   值是对应的数量

        //把套餐数量存到map里
        map.put("setmealCount", list);
        List<String> setmealNames = new ArrayList<>();
        //3:遍历所有套餐 获取每一个名字
        for (Map<String, Object> objectMap : list) {
            //通过键找值
            String name = (String) objectMap.get("name");
            //把名字加入到所有套餐名的集合里
            setmealNames.add(name);
        }
        //把套餐名加入到套餐的map里
        map.put("setmealNames", setmealNames);
        //4:返回数据
        return new Result(true, MessageConst.GET_SETMEAL_COUNT_REPORT_SUCCESS, map);//map是套餐名 和 值
    }

    /**
     * 向表里导入数据
     * @throws IOException
     */
    @GetMapping("/exportBusinessReport")
    public Result exportBusinessReport(HttpServletResponse response) throws IOException {




//调用方法
        OperationDataStatistics operationDataStatistics = reportService.getOperationDataStatistics();
        log.info("获取的数据,{}",operationDataStatistics);
        List<Map> hotSetmeal = operationDataStatistics.getHotSetmeal();
//在内存中创建一个Excel文件
        //在内存中创建一个Excel文件(绑定模板文件)
        //XSSFWorkbook workbook = null;
        try {
            //通过反射资源流的方式, 读取resources下的报表模板
            InputStream in = this.getClass().getClassLoader().getResourceAsStream("report_template.xlsx");
           Workbook workbook = new XSSFWorkbook(in);


            Sheet sheet = workbook.getSheetAt(0);


            Row row = sheet.getRow(2);
            String reportDate = operationDataStatistics.getReportDate();
        System.out.println(reportDate);
        row.getCell(5).setCellValue(reportDate);
//5行
            Row row1=sheet.getRow(4);
            Integer todayNewMember = operationDataStatistics.getTodayNewMember();
            row1.getCell(5).setCellValue(todayNewMember);
            Integer totalMember = operationDataStatistics.getTotalMember();
            sheet.getRow(4).getCell(7).setCellValue(totalMember);
//6
            Integer thisWeekNewMember = operationDataStatistics.getThisWeekNewMember();
            Integer thisMonthNewMember = operationDataStatistics.getThisMonthNewMember();
            sheet.getRow(5).getCell(5).setCellValue(thisWeekNewMember);
            sheet.getRow(5).getCell(7).setCellValue(thisMonthNewMember);
            //8
            Integer todayOrderNumber = operationDataStatistics.getTodayOrderNumber();
            Integer todayVisitsNumber = operationDataStatistics.getTodayVisitsNumber();
            sheet.getRow(7).getCell(5).setCellValue(todayOrderNumber);
            sheet.getRow(7).getCell(7).setCellValue(todayVisitsNumber);
            //9
            Integer thisWeekOrderNumber = operationDataStatistics.getThisWeekOrderNumber();
            Integer thisWeekVisitsNumber = operationDataStatistics.getThisWeekVisitsNumber();
            sheet.getRow(8).getCell(5).setCellValue(thisWeekOrderNumber);
            sheet.getRow(8).getCell(7).setCellValue(thisWeekVisitsNumber);
            //10
            Integer thisMonthOrderNumber = operationDataStatistics.getThisMonthOrderNumber();
            Integer thisMonthVisitsNumber = operationDataStatistics.getThisMonthVisitsNumber();
            sheet.getRow(9).getCell(5).setCellValue(thisMonthOrderNumber);
            sheet.getRow(9).getCell(7).setCellValue(thisMonthVisitsNumber);

            //12-13
            int num=12;
            for (Map<String, Object> setmeal : hotSetmeal) {
                String name =(String) setmeal.get("name");
                BigDecimal proportion =(BigDecimal) setmeal.get("proportion");
                Long setmeal_count =(Long) setmeal.get("setmeal_count");
                sheet.getRow(num).getCell(4).setCellValue(name);
                sheet.getRow(num).getCell(5).setCellValue(setmeal_count);
                sheet.getRow(num).getCell(6).setCellValue(proportion.toString());
                num++;
            }
//            Row row1 = sheet.getRow(4);
//          Integer todayNewMember = operationDataStatistics.getTodayNewMember();
//          row.getCell(5).setCellValue(todayNewMember);


            //设置以附件形式打开的响应头, 下载的报表名称为report.xls
    response.setContentType("application/vnd.ms-excel;chartset=utf-8");
    response.setHeader("Content-Disposition", "attachment;filename=report.xls");
    //通过输出流将workbook对象输出到磁盘
    OutputStream out = response.getOutputStream();
    workbook.write(out);
    out.flush();//清空缓冲区
    out.close();
    workbook.close();

            return new Result(true,MessageConst.ACTION_SUCCESS);
        } catch (IOException e) {
            e.printStackTrace();
            return new Result(false,MessageConst.ACTION_FAIL);
        }
        }



    @Autowired
    private ReportService reportService;


            /*
             *     运营数据统计   显示
             *
             * */
            @GetMapping("/getBusinessReportData")
            public Result operationDataStatistics() {
                log.info("执行了!!!!!运营数据统计");
                OperationDataStatistics operationDataStatistics = reportService.getOperationDataStatistics();

                return new Result(true, MessageConst.ACTION_SUCCESS, operationDataStatistics);
            }

    @GetMapping("/getMemberReport")
    public Result getMemberReport() throws JobExecutionException {
        //从redis中取出map集合
        Map<String, Object> redisMap = redisTemplate.opsForHash().entries("map");
        log.info("第一次取出的存在redis中的map为：{}", redisMap);
        if (redisMap == null || redisMap.size() == 0) {
            updateMap();
            redisMap = redisTemplate.opsForHash().entries("map");
            log.info("第二次取出的存在redis中的map为：{}", redisMap);
        }
        return new Result(true, MessageConst.GET_MEMBER_NUMBER_REPORT_SUCCESS, redisMap);
    }

    /**
     * 这个功能是完成定时把会员总数按照天或月的维度把数据跑出来
     *
     * @throws JobExecutionException
     */
    //测试用
    /* @Scheduled(cron = "0 0/3 * * * ? ")//每三分钟触发一次*/
    @Scheduled(cron = "0 0 6 * * ?")//每天六点更新数据
    public void updateMap() throws JobExecutionException {
        //先判断一下redis中有没有之前的数据
        //从redis中取出map集合
        Map<String, Object> redisMap = redisTemplate.opsForHash().entries("map");
        try {
            if (redisMap != null) {
                //删除集合中的数据
                log.info("删除的redisMap为：{}", redisMap);
                redisTemplate.delete("map");
            }
            //根据请求参数可以使用两个集合接受参数
            List<String> months = new ArrayList<>();//这个用来接受月份
            List<Integer> memberCount = new ArrayList<>();//这个用来接受会员数量的，以月份为单位
            memberCount = null;
            //这里使用Calendar类，Calendar是一个日历类（用于表示一个时间点）里面提供了很多获取/操作时间的方法
            Calendar c = Calendar.getInstance();
            //获取从当前月开始的前第i个月:c.add(Calendar.MONTH, -i);
            c.add(Calendar.MONTH, -11);//获取第前11个月，显示到当前月；改为-12显示到上个月
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM");//月份转换模板
            log.info("当前月的第前12个月为：{}", sdf.format(c.getTime()));
        /*int maximum = c.getActualMaximum(Calendar.DAY_OF_MONTH);
        log.info("本月最后一天为：{}",maximum);*/
        /*c.add(Calendar.MONTH,1);
        log.info("当前月的第前11个月为：{}",sdf.format(c.getTime()));*/
            Map<String, Integer> lastDays = new HashMap<>();//保存月份对应的最大天数
            //循环12次，依次取出每月的月份存入集合，并把获取的月份+1
            for (int i = 0; i < 12; i++) {
                Date time = c.getTime();
                //获取该月的最后一天
                Integer maximum = c.getActualMaximum(Calendar.DAY_OF_MONTH);
                //使用模板转换
                String month = sdf.format(time);
                //存入月份的集合
                months.add(month);
                //把月份已经对应的总天数存入map集合
                lastDays.put(month, maximum);
                //获取下一月份时间
                c.add(Calendar.MONTH, 1);
            }
            log.info("月份为：{}", months.size());

            //这里月份就依次取完了
            //写memberCount集合，这个是关于会员数量的
            memberCount = memberService.countByMonth(months, lastDays);
            //把获得的月份和数量存入map

            Map<String, Object> map = new HashMap<>();
            map.put("months", months);
            map.put("memberCount", memberCount);
            log.info("存入redis中的map为：{}", map);
            //把map集合存入redis中
            redisTemplate.opsForHash().putAll("map", map);
        } catch (Exception e) {
            e.printStackTrace();
            JobExecutionException e2 = new JobExecutionException(e);
            // 这个工作将立即重新开始
            e2.setRefireImmediately(true);
            throw e2;
        }
    }
}
